import path from "path"
import fs from "fs-extra"

import puppeteer, { Page } from "puppeteer-core"
import { biliTrace, biliSuccess, sendEmail } from "@/services"

import { getLastPage, transform2WinPath } from "@/utils"
import { fullScreenChrome, desktopPath } from "@/utils"

/**
 *
 * @param resource bili目录
 *
 * @example
 * resource = /Users/kenny/Desktop/t_03/精神障碍护理学/bili
 */
const main = async (resource: string, cacheName: string) => {
  biliTrace.info("----------------------------------------")

  const folder = path.dirname(resource).replace(desktopPath, "")

  biliTrace.warn(1, folder, "进入流程")

  const jsonPath = path.join(resource, "b.json")

  // const json = JSON.parse(fs.readFileSync(jsonPath, { encoding: "utf8" }))
  const json = fs.readJSONSync(jsonPath)

  biliTrace.trace("2、切换到", cacheName, "缓存目录", "启动浏览器实例")

  const userDataDir = path.join(".cache", cacheName)

  const browser = await puppeteer.launch({
    headless: false,
    channel: "chrome",
    defaultViewport: null,
    userDataDir,

    args: [
      // "--disable-gpu",
      // "--disable-dev-shm-usage",
      // "--no-first-run",
      // "--no-zygote",
      // "--single-process",

      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-notifications",
      "--disable-extensions",
    ],
  })

  biliTrace.trace("3、打开：B站首页")

  const [page] = await browser.pages()

  await page.goto("https://www.bilibili.com/", { waitUntil: "load" })

  biliTrace.warn("4、执行：浏览器全屏脚本")
  fullScreenChrome()

  /**
   * 循5秒环检测登录状态
   */
  biliTrace.trace("5、循环检测登录状态")

  while (Date.now()) {
    const loginBtn = await page.$('.header-login-entry::-p-text("登录")')

    if (loginBtn) {
      biliTrace.info(folder, "未登录", "点击登录按钮，唤起登录框", "等待15s")
      await loginBtn.click()
      await page.waitForTimeout(15000)
    } else {
      biliTrace.warn(folder, "已经登录", "结束登录状态循环监听")
      break
    }
  }

  biliTrace.trace("点击头像跳转到个人主页")

  const avatar = await page.$(".header-entry-avatar")

  await page.evaluate(el => {
    ;(<HTMLElement>el).click()
  }, avatar)

  await avatar?.dispose()

  biliTrace.trace("检测个人简介是否被删")

  await page.waitForTimeout(3000)

  const spacePage = <Page>await getLastPage(browser)

  await spacePage.waitForTimeout(10000)

  await spacePage.locator(".h-sign").wait()

  const sign = await spacePage.$(".h-sign")

  const signHtml = await spacePage.evaluate(el => el?.innerHTML, sign)

  biliTrace.trace("signHtml", signHtml)

  const isIntroduceOk = ["铭美", "学道宝典"].some(i => signHtml?.includes(i))

  console.log("AT-[ 简介是否被删除 ]", isIntroduceOk)

  await sign?.dispose()

  await spacePage.close()

  !isIntroduceOk &&
    (await sendEmail({
      subject: `⚠️⚠️⚠️ ${folder}`,
      text: "简介掉了",
    }))

  biliTrace.trace("6、", folder, "点击：上传按钮,等待页面跳转")

  /**
   * 点击并且监听浏览器跳转事件
   */
  await new Promise(resolve => {
    page.once("popup", async newPage => {
      await newPage?.waitForSelector("body")
      resolve(null)
    })

    page
      .locator(".right-entry-item--upload")
      .setTimeout(0)
      .click({ delay: 2000 })
  })

  biliTrace.trace("7、", "关闭：关闭首页")
  await page.close()

  biliTrace.trace("8、", "拿到新页面实例")
  const uploadPage = <Page>await getLastPage(browser)

  /**禁止打开新页面 防止异常出现*/
  browser.on("targetcreated", target => {
    target.page().then(n => n?.close())
  })

  biliTrace.info("9、", "进入上传流程")

  biliTrace.info("~~", "开始上传视频")

  const [videoFileChooser] = await Promise.all([
    uploadPage.waitForFileChooser(),

    uploadPage.locator(".bcc-upload-wrapper").click(),
  ])

  const mp4Path = path
    .join(transform2WinPath(json.mp4Path))
    .replace("products", "")

  biliTrace.info("mp4Path", mp4Path)

  await videoFileChooser.accept([mp4Path])

  biliTrace.trace("~~", "等待60s", "为了确保封面图上传图片出现")

  await Promise.any([
    uploadPage.locator(".success::-p-text(上传完成)").wait(),

    uploadPage.locator(".icon-sprite-pause").click(),
  ])

  biliTrace.info("10、", "开始上传封面图", "将底层input展示出来后等2s再点击")

  const coverUploadBtn = await uploadPage.evaluateHandle(() => {
    const input = $(".cover-upload .bcc-upload-wrapper input")

    input.css({
      display: "block",
      padding: "50px",
      position: "absolute",
      top: 0,
      left: 0,
      zIndex: 999,
      background: "red",
    })

    return input.get(0) as HTMLElement
  })

  /**
   * 滚动到上传图片标签可视区域
   */
  await coverUploadBtn?.scrollIntoView()

  await uploadPage.waitForTimeout(2000)

  const [coverImageFileChooser] = await Promise.all([
    uploadPage.waitForFileChooser(),

    coverUploadBtn?.click(),
  ])

  const coverPngPath = transform2WinPath(json.coverPngPath).replace(
    "products",
    "",
  )

  biliTrace.info("coverPngPath", coverPngPath)

  await coverImageFileChooser?.accept([coverPngPath])

  await uploadPage.locator(".bcc-button span::-p-text( 完成 )").click()

  biliTrace.trace("~~", "完成上传封面图")

  /**
   * 判断视频是否已上传完毕
   * 若已没有传完则：继续上传视频
   */
  await uploadPage.evaluateHandle(() => {
    if (!$(".success:contains(上传完成)").length) {
      $(".file-block-icon-bg:has(.icon-sprite-play)").click()
    }
  })

  biliTrace.trace("11、", "等待3s")

  await uploadPage.waitForTimeout(3000)

  const inputTitle = await uploadPage.waitForSelector(
    ".input-instance .input-val",
  )

  biliTrace.trace("~~", "等标题输入框出现后，将其滚动到可视区域再连续点击3次")

  await inputTitle?.scrollIntoView()

  await inputTitle?.click({ count: 3 })

  biliTrace.trace("12、", "等待100ms", "输入：标题")

  await uploadPage.type(".input-instance .input-val", json.name, { delay: 100 })

  const isNeedSelectArea = await uploadPage.evaluate(
    () => !$(".select-item-cont-inserted:contains( 知识 → 校园学习)").length,
  )

  biliTrace.info("~~", "是否需要选择：知识-校园学习", isNeedSelectArea)

  if (isNeedSelectArea) {
    biliTrace.info("14、", "等待3s", "点击：分区选择框右边的下拉图标按钮")
    await uploadPage.waitForTimeout(3000)

    const pulldownBtn = await uploadPage.evaluateHandle(() => {
      const pulldownBtn = <Element>$(".video-type .icon-sprite-pulldown").get(0)

      const rect = pulldownBtn.getBoundingClientRect()

      document.documentElement.scrollTop = rect.top / 2

      return pulldownBtn
    })

    await pulldownBtn.scrollIntoView()

    await pulldownBtn.click()

    biliTrace.trace("~~", "等待3s", "选择：知识")

    await uploadPage.waitForTimeout(3000)

    // await new Promise(r => setTimeout(r, 999999))
    await uploadPage.evaluate(() => {
      $(".drop-f-item:contains(知识)").click()
    })

    biliTrace.trace("~~", "等待3s", "选择：校园学习")

    await uploadPage.waitForTimeout(3000)

    await uploadPage.evaluate(() => {
      $(".item-main:contains(校园学习)").click()
    })
  }

  await uploadPage.waitForTimeout(3000)
  biliTrace.trace("~~", "等待标签输入框出现")

  await uploadPage.evaluate(() => {
    const input = <HTMLElement>(
      $('input[placeholder="按回车键Enter创建标签"]').get(0)
    )

    const rect = input.getBoundingClientRect()
    document.documentElement.scrollTop = rect.top / 2
  })

  biliTrace.trace("15、", "循环输入标签", "每隔3s输入一个")

  for (const tagValue of json.tags) {
    await uploadPage.type(
      'input[placeholder="按回车键Enter创建标签"]',
      tagValue,
      {
        delay: 500,
      },
    )

    await uploadPage.keyboard.press("Enter", { delay: 3000 })
  }

  await uploadPage.waitForTimeout(3000)

  biliTrace.info("17、", "输入：视频描述内容")

  await uploadPage.evaluate(function (text) {
    const editor = <HTMLInputElement>$(".ql-editor p").get(0)

    const editorRect = editor.getBoundingClientRect()

    document.documentElement.scrollTop = editorRect.top / 2

    editor.innerHTML = text
  }, json.desc)

  biliTrace.info("18、", "等待：上传完成", "暂时不考虑上传失败等特殊情况")

  /**
   * 最多等待15分钟
   */
  await uploadPage
    .locator(".success::-p-text(上传完成)")
    .setTimeout(15 * 60 * 1000)
    .wait()

  biliTrace.trace("19、", "上传完成", "点击：立即投稿按钮")

  await Promise.any([
    uploadPage.locator(".submit-add::-p-text(立即投稿)").click(),

    uploadPage.evaluate(() => {
      $(".submit-add").click()
    }),
  ])

  biliTrace.info("20、", "等待投稿结果")
  await Promise.any([
    uploadPage.locator("::-p-text(恭喜你上传第一个稿件，成为UP主~)").wait(),

    uploadPage.locator(".step-des::-p-text(稿件投递成功)").wait(),
  ])

  biliTrace.info("21、", "投稿成功，关闭浏览器实例")
  await browser.close()

  biliTrace.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", "\r\n\r\n")
  biliSuccess.fatal(resource, cacheName)
}

export default main
